import re
import logging
from logging.handlers import TimedRotatingFileHandler
import codecs
import sys
import os
import time
import glob


class TimedRotatingCompressedFileHandler(TimedRotatingFileHandler):

    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False,
                 atTime=None, compression="gz", limit_size=1024 * 1024 * 300):
        TimedRotatingFileHandler.__init__(self, filename, when, interval, backupCount, encoding,
                                          delay, utc, atTime)

        self._compression = compression
        self._limit_size = limit_size

    def getFilesToDelete(self):
        """
        Determine the files to delete when rolling over.

        More specific than the earlier method, which just used glob.glob().
        """
        dirName, baseName = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        # See bpo-44753: Don't use the extension when computing the prefix.
        prefix = baseName + "."
        plen = len(prefix)

        total_file_size = 0
        for fileName in fileNames:
            if fileName[:plen] == prefix:
                suffix = fileName[plen:]
                filePath = os.path.join(dirName, fileName)

                filePath, fileSize = self.compress(filePath, fileName)
                total_file_size += fileSize

                if self.extMatch.match(suffix):  # 根据文件+. 是否在 suffix
                    result.append(filePath)
                    continue

                if total_file_size >= self._limit_size:
                    result.append(os.path.join(dirName, fileName))

        if len(result) < self.backupCount:
            result = []
        else:
            result.sort()
            result = result[:len(result) - self.backupCount]
        return result

    def compress(self, filePath, fileName):
        file_size = 0
        newFilePath = filePath
        if self._compression == "gz":
            newFilePath, file_size = self.gz_file(filePath, fileName)
        elif self._compression == "zip":
            newFilePath, file_size = self.zip_file(filePath, fileName)
        else:
            try:
                file_size = os.stat(filePath).st_size
            except:
                file_size = 0

        return newFilePath, file_size

    def zip_file(self, filePath, fileName):
        import zipfile

        file_size = os.stat(filePath).st_size
        newFilePath = filePath
        if not filePath.endswith('.gz') and not filePath.endswith('.zip'):
            zip_file_path = filePath + '.zip'
            try:
                z = zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED)
                z.write(filePath, fileName)
                os.remove(filePath)
                newFilePath = zip_file_path

                file_size = os.stat(zip_file_path).st_size
            except Exception as e:
                print('文件zip压缩失败: ', e)
            finally:
                z.close()

        return newFilePath, file_size

    def gz_file(self, filePath, fileName):
        """
        :param filePath: 待压缩的文件全路径
        :param fileName: 待压缩的文件名
        :return:
        """
        import gzip

        file_size = os.stat(filePath).st_size
        newFilePath = filePath
        if not filePath.endswith('.gz') and not filePath.endswith('.zip'):
            zip_file_path = filePath + '.gz'  # 压缩后文件名
            try:
                ftime = os.stat(filePath).st_mtime
                zf = gzip.GzipFile(zip_file_path, mode='wb', mtime=ftime)

                with open(filePath, 'rb') as f_ungz:  # 打开待压缩文件，生成文件对象，注意二进制读取
                    zf.writelines(f_ungz)  # 将打开待压缩文件对象写入到压缩文件对象流

                os.remove(filePath)
                newFilePath = zip_file_path

                zf.flush()   # 此处必须调用才会写数据到磁盘中 st_size才会有正确的文件大小
                file_size = os.stat(zip_file_path).st_size
            except Exception as e:
                print('文件gz压缩失败: ', e)
            finally:
                zf.close()

        return newFilePath, file_size